package cn.tellfish.studydemo.demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;

public class NioServer {


    public static WorkThread[] workThreads = new WorkThread[3];

    public static void main(String[] args) {

        BossThread bossThread = new BossThread(8080);
        for (int i = 0; i < workThreads.length; i++) {
            WorkThread workThread = new WorkThread();
            workThreads[i] = workThread;
            workThread.start();
        }
        bossThread.start();


        try {
            //main 等 boss 结束之后才结束
            bossThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}


class BossThread extends Thread {

    ServerSocketChannel server;
    Selector selector;

    public BossThread(int port) {
        try {
            server = ServerSocketChannel.open();
            // 手动设置为 nio
            server.configureBlocking(false);
            server.bind(new InetSocketAddress(port));
            System.out.println("nio启动" + port);
            // selector 实现一个线程处理多个连接的关键类
            // 从操作系统底层 选取我们需要处理的连接（事件通知）
            selector = Selector.open();
            //如果有新连接就通过selector通知我
            server.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void run() {
        try {
            while (true) {
                //有多少新连接过来了
                int count = selector.select(1000);
                if (count == 0) {
                    continue;
                }
                //符合条件的通知
                Set<SelectionKey> selectionKeys = selector.selectedKeys();

                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey next = iterator.next();
                    if (!next.isAcceptable())
                        continue;
                    //拿到新连接
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    //谁来处理这个连接
                    int rdm = new Random().nextInt(NioServer.workThreads.length);
                    NioServer.workThreads[rdm].processSocket(socketChannel);
                    System.out.println("有新的连接了。。。");

                }
                selectionKeys.clear();
                selector.selectNow();

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

class WorkThread extends Thread {

    private Selector selector;

    public WorkThread() {
        try {
            selector = Selector.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void processSocket(SocketChannel socketChannel) {
        try {
            socketChannel.register(selector, SelectionKey.OP_READ);
        } catch (ClosedChannelException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            while (true) {
                int count = selector.select(1000);
                if (count == 0) {
                    continue;
                }
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey next = iterator.next();
                    if (next.isReadable()) {
                        SocketChannel clientSocketChannel = (SocketChannel) next.channel();
                        clientSocketChannel.configureBlocking(false);
                        {
                            ByteBuffer requestBuffer = ByteBuffer.allocate(1024);
                            clientSocketChannel.read(requestBuffer);
                            String request = new String(requestBuffer.array());
                            System.out.println(Thread.currentThread().getName());
                            System.out.println("收到的内容" + request);
                        }
                    }
                }
                selectionKeys.clear();
                selector.selectNow();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}